﻿using System.Diagnostics;
using System.Threading;
using HK.Core.Common;
using HK.Core.Threader.Protocol;

namespace HK.Core.Threader
{
    /// <summary>
    /// 线程执行器
    /// </summary>
    public abstract class Threader : ClassExtension, IThreader
    {
        
        /// <summary>
        /// 线程ID
        /// </summary>
        public int ThreadId => Executor?.ManagedThreadId ?? -1;

        /// <summary>
        /// 线程名
        /// </summary>
        public string ThreadName => Executor?.Name;

        /// <summary>
        /// 有效标志位
        /// </summary>
        public virtual bool Valid => -1 != ThreadId;

        /// <summary>
        /// 权限
        /// </summary>
        public ThreadPriority Priority { get; protected set; } = ThreadPriority.Normal;

        /// <summary>
        /// 已激活标志位
        /// </summary>
        public bool Activated
        {
            get
            {
                if (Sleeping || Executing) return true;
                var isThreadAlive = Executor?.IsAlive ?? false;
                return isThreadAlive;
            }
        }
        
        /// <summary>
        /// 成功标志位
        /// </summary>
        public bool Succeeded { get; protected set; } = false;

        /// <summary>
        /// 取得线程执行器名
        /// </summary>
        /// <returns>线程执行器名</returns>
        public virtual string GetThreaderName()
        {
            return GetType().Name;
        }

#region Init
        
        /// <summary>
        /// 初始化标志位
        /// </summary>
        public bool Initialized { get; protected set; } = false;
        
        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="iCurrent">当前执行</param>
        /// <param name="iPrev">执行前预处理</param>
        /// <param name="iNext">执行后处理</param>
        /// <returns>true:OK; false:NG;</returns>
        protected virtual bool Init(ThreadCurOperation iCurrent = null,
            ThreadPrevOperation iPrev = null, ThreadNextOperation iNext = null)
        {
            // 初始化操作
            InitOperations(iCurrent, iPrev, iNext);
            Initialized = true;
            return null != CurOperation;
        }

        /// <summary>
        /// 初始化操作
        /// </summary>
        /// <param name="iCurrent">当前执行</param>
        /// <param name="iPrev">执行前预处理</param>
        /// <param name="iNext">执行后处理</param>
        protected void InitOperations(ThreadCurOperation iCurrent = null,
            ThreadPrevOperation iPrev = null, ThreadNextOperation iNext = null)
        {
            PrevOperation = iPrev ?? PrevExecute;
            CurOperation = iCurrent ?? CurExecute;
            NextOperation = iNext ?? NextExecute;
        }

#endregion

#region CostTimes

        /// <summary>
        /// 消耗时间
        /// <para>* 单位：毫秒</para>
        /// </summary>
        public long CostTime { get; protected set; } = 0L;
        
        /// <summary>
        /// 时间监控器
        /// </summary>
        public Stopwatch TimeWatch { get; } = new Stopwatch();

#endregion

#region Prev

        /// <summary>
        /// 执行前预处理
        /// </summary>
        public ThreadPrevOperation PrevOperation { get; private set; } = null;

        /// <summary>
        /// 执行前预处理
        /// <para>* 挂起睡眠等待时间间隔，默认值:500毫秒</para>
        /// </summary>
        /// <returns>true:待机，进入睡眠状态; false:中止待机，继续向下执行;</returns>
        protected virtual bool PrevExecute()
        {
            // 若初始化尚未完成，则进入睡眠待机
            if (!Initialized) return true;
            
            // 若是暂停，则进入睡眠状态
            if (Paused) return true;
            return false;
        }
        
#endregion

#region Current
        
        /// <summary>
        /// 线程当前处理
        /// </summary>
        public ThreadCurOperation CurOperation { get; private set; } = null;

        /// <summary>
        /// 线程当前处理
        /// </summary>
        /// <returns>true:执行成功; false:执行失败;</returns>
        protected abstract bool CurExecute();

#endregion

#region Next
        
        /// <summary>
        /// 执行后处理
        /// </summary>
        public ThreadNextOperation NextOperation { get; private set; } = null;

        /// <summary>
        /// 执行后处理
        /// </summary>
        /// <param name="iSucceed">执行成功标志位</param>
        /// <returns>true:继续执行; false:不用继续执行;</returns>
        protected virtual bool NextExecute(bool iSucceed)
        {
            // 被停止
            if (Stopped)
            {
                Executing = false;
                return false;
            }
            
            // 被取消
            if (Canceled) 
            {
                Executing = false;
                return false;
            }
            
            // 被中断
            if (Interrupted)
            {
                Executing = false;
            }
            return !Interrupted;
        }

#endregion

#region Execute

        /// <summary>
        /// 执行中
        /// </summary>
        public bool Executing { get; protected set; } = false;

        /// <summary>
        /// 线程执行者
        /// </summary>
        public Thread Executor { get; private set; } = null;
        
        /// <summary>
        /// 执行
        /// </summary>
        public void Execute()
        {
            if(Executing) return;
            
            // 耗时监控
            TimeWatch.Stop();
            
            // 开启子线程下载,使用匿名方法
            Executor = new Thread(delegate()
            {
                while (true)
                {
                    // 已经被停止/中断了
                    if (Interrupted)
                    {
                        // 中止线程
                        Abort();
                        break;
                    }
			        
                    // 已经被取消了
                    if (Canceled)
                    {
                        // 中止线程
                        Abort();
                        break;
                    }
                    
                    // 重新开始计数
                    TimeWatch.Restart();
                    CostTime = 0L;
                    
                    // 预处理
                    if (null != PrevOperation)
                    {
                        // 执行预处理
                        Sleeping = PrevOperation.Invoke();
                    }
                        
                    // 需要继续睡眠待机，则返回
                    if (Sleeping)
                    {
                        Thread.Sleep(SleepInterrupt);
                        continue;   
                    }
                    
                    // 已经被停止/中断了
                    if (Interrupted)
                    {
                        // 消耗时间监控
                        TimeWatch.Stop();
                        CostTime = TimeWatch.ElapsedMilliseconds;
                        
                        // 中止线程
                        Abort();
                        break;
                    }
			        
                    // 已经被取消了
                    if (Canceled)
                    {
                        // 消耗时间监控
                        TimeWatch.Stop();
                        CostTime = TimeWatch.ElapsedMilliseconds;
                        
                        // 中止线程
                        Abort();
                        break;
                    }
                    
                    // 执行内容
                    Succeeded = CurOperation();
                    
                    // 已经被停止/中断了
                    if (Interrupted)
                    {
                        // 消耗时间监控
                        TimeWatch.Stop();
                        CostTime = TimeWatch.ElapsedMilliseconds;

                        // 中止线程
                        Abort();
                        break;
                    }
			        
                    // 已经被取消了
                    if (Canceled)
                    {
                        // 消耗时间监控
                        TimeWatch.Stop();
                        CostTime = TimeWatch.ElapsedMilliseconds;

                        // 中止线程
                        Abort();
                        break;
                    }
                
                    // 执行成功
                    var needContinue = NextOperation?.Invoke(Succeeded) ?? false;
                    
                    // 消耗时间监控
                    TimeWatch.Stop();
                    CostTime = TimeWatch.ElapsedMilliseconds;
                    
                    if (needContinue)
                    {
                        Thread.Sleep(SleepInterrupt);
                        continue;
                    }
                    break;
                }

                // 执行完毕
                TimeWatch.Stop();
                CostTime = TimeWatch.ElapsedMilliseconds;
                
                Stopped = true;
                Executing = false;
                Sleeping = false;

                // 线程正常结束
                OnFinished();
                
            })
            {
                IsBackground = true, Priority = Priority, 
                Name = GetThreaderName()
            };
            
            // 启动线程
            if (!Executor.IsAlive)
            {
                Executing = true;
                Interrupted = false;
                Executor.Start(); 
            }
        }

#endregion

#region Pause
        
        /// <summary>
        /// 暂停标志位
        /// </summary>
        public virtual bool Paused { get; protected set; } = false;
        
        /// <summary>
        /// 睡眠待机标志位
        /// <para>* 该线程会挂起，睡眠等待一定时间间隔后，在次启动。即:SleepInterrupt</para>
        /// <para>* true : 可以开始运行</para>
        /// <para>* false : 待机100毫秒后，继续执行</para>
        /// </summary>
        public bool Sleeping { get; private set; } = true;

        /// <summary>
        /// 睡眠挂起等待时间间隔
        /// <para>* 单位:毫秒(默认:500毫秒)</para>
        /// </summary>
        public int SleepInterrupt { get; protected set; } = 500;

        /// <summary>
        /// 暂停
        /// </summary>
        public virtual void Pause()
        {
            Paused = true;
        }
        
#endregion
        
        /// <summary>
        /// 恢复
        /// </summary>
        public virtual void Resume()
        {
            Paused = false;
        }

#region Cancel

        /// <summary>
        /// 取消标志位
        /// <para>* 即便当前有任务在执行中，也中断</para>
        /// </summary>
        public bool Canceled { get; protected set; } = false;
        
        /// <summary>
        /// 中断标志位
        /// <para>* 执行中断，但是尚未完全停下来</para>
        /// <para>* 若当前任务执行中，则等待执行完毕再中断</para>
        /// </summary>
        public bool Interrupted { get; protected set; } = false;

        /// <summary>
        /// 取消
        /// </summary>
        public virtual void Cancel()
        {
            Canceled = true;
        }

#endregion

#region Stop
        
        /// <summary>
        /// 完成标志位
        /// </summary>
        public bool Stopped { get; protected set; } = false;

        /// <summary>
        /// 停止
        /// <para>* 若当前有任务在执行中，则当代任务执行完毕再</para>
        /// </summary>
        public virtual void Stop()
        {
            Interrupted = true;
            Sleeping = false;
        }
        
        /// <summary>
        /// 中止线程
        /// </summary>
        public virtual void Abort()
        {
            var lastThread = Executor;
            Executor = null;
            
            // 消耗时间监控
            TimeWatch.Stop();
            CostTime = TimeWatch.ElapsedMilliseconds;
                
            // 执行完成
            Stopped = true;
            Executing = false;
            Sleeping = false;

            // 中止上一次启动的线程
            lastThread?.Abort();
        }

#endregion

        /// <summary>
        /// 线程正常结束
        /// </summary>
        protected virtual void OnFinished() {  }

        /// <summary>
        /// 释放
        /// </summary>
        public virtual void Dispose()
        {
            // 停止时间监测
            TimeWatch.Stop();

            CostTime = 0L;
            Executing = false;
            Interrupted = false;
            Canceled = false;

            // 停止
            Stop();
        }
    }
}
